package com.eco.fanliapp.admin.security.filter;


import com.alibaba.fastjson.JSONObject;
import com.eco.fanliapp.admin.exception.TokenException;
import com.eco.fanliapp.common.constant.ApiEnum;
import com.eco.fanliapp.common.response.ServerResponse;
import com.eco.fanliapp.entity.MenuInfo;
import com.eco.fanliapp.entity.RoleInfoMenus;
import com.eco.fanliapp.admin.security.constant.ConstantKey;
import com.eco.fanliapp.service.IMenuInfoService;
import com.eco.fanliapp.service.IRoleInfoMenusService;
import com.eco.fanliapp.vo.UserVO;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 自定义JWT认证过滤器
 * 该类继承自BasicAuthenticationFilter，在doFilterInternal方法中，
 * 从http头的Authorization 项读取token数据，然后用Jwts包提供的方法校验token的合法性。
 * 如果校验通过，就认为这是一个取得授权的合法请求
 *
 * @author zhaoxinguo on 2017/9/13.
 */
@Component
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    @Autowired
    private static IRoleInfoMenusService roleInfoMenusService;
    @Autowired
    private static IMenuInfoService menuInfoService;

    private static final Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
    private static final List<String> roleList = new ArrayList<String>() {{
        add("/back/subUser/findRoleList");
        add("/back/subUser/findAllByUserId");
        add("/web/find/commpany/list");
        add("/web/goodsTop/findAll");
        add("/web/goodsFree/findAll");
        add("/web/pushInfo");
        add("/web/bannerPicture");
        add("/web/commissionFreeze/selectByTableId");
        add("/web/qiniu/info,/web/order/fee/scheme/all");
        add("/web/appGeneralfeescheme/findGeneralfeeschemeAll");
        add("/web/taobaoplan/find/taobaoplan/all");
        add("/web/user/findUserList");
        add("/web/order/selectAppOrderDetailList");
        add("/web/withdrawal/selectWithdrawalList");
        add("/msg/template/find/msg/template/all");
        add("/web/version/selectAppVersionList");
        add("/web/friends/selectWebCircleFriendsList");
        add("/web/goods/findAll");
    }};

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String header = request.getHeader("Authorization");
        if (header == null) {
//        	return403(response, "Token为空");
            try {
                chain.doFilter(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return;
        }
        String requestURI = request.getRequestURI();
        UsernamePasswordAuthenticationToken  authentication = getWebAuthentication(request, response);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(request, response);
    }

    //校验token
    private UsernamePasswordAuthenticationToken getWebAuthentication(
            HttpServletRequest request, HttpServletResponse response) {
        //long start = System.currentTimeMillis();
        String token = request.getHeader("Authorization");
        if (token == null || token.isEmpty()) {
            throw new TokenException("Token为空");
            //return403(response,"token为空");
        }
        String user = null;
        try {
            user = Jwts.parser()
                    .setSigningKey(ConstantKey.SIGNING_KEY)
                    .parseClaimsJws(token.replace(ApiEnum.JWT_KEY.replace(" ", ""), "").trim())
                    .getBody()
                    .getSubject();

            //long end = System.currentTimeMillis();
            //logger.info("执行时间: {}", (end - start) + " 毫秒");
            if (user != null) {
                UserVO userVO = null;
                try {
                    userVO = JSONObject.parseObject(user, UserVO.class);
                } catch (Exception e) {
                    return new UsernamePasswordAuthenticationToken(user, null, null);
                    // TODO: handle exception
                }

                if (userVO.getRoleId() == null || userVO.getRoleId() == 0) {
                    return new UsernamePasswordAuthenticationToken(user, null, null);

                } else {
                    RoleInfoMenus req = new RoleInfoMenus();
                    req.setRoleinfoId(userVO.getRoleId());
                    List<RoleInfoMenus> menuInfos = roleInfoMenusService.selectRoleInfoMenusList(req);
                    String roleUrl = "";
                    for (RoleInfoMenus menuInfo1 : menuInfos
                    ) {
                        MenuInfo menuInfo2 = menuInfoService.selectMenuInfoById(menuInfo1.getMenusId());
                        roleUrl += menuInfo2.getAlias();
                    }
                    List<String> list = Arrays.asList(roleUrl.split(","));
                    roleList.removeAll(list);
                    if (roleList.contains(request.getRequestURI())) {
                        logger.error("权限错误");
                        throw new TokenException("权限错误");
                        //return403(response,"权限错误");
                    } else {
                        return new UsernamePasswordAuthenticationToken(user, null, null);
                    }
                }
            }

        } catch (ExpiredJwtException e) {
            logger.error("Token已过期: {} " + e);
            //throw new TokenException("Token已过期");
            //return403(response, "登录过期请重新登录！");
            return505(response,"Token已过期");
        } catch (UnsupportedJwtException e) {
            logger.error("Token格式错误: {} " + e);
            throw new TokenException("Token格式错误");
            //return403(response,"Token格式错误");
        } catch (MalformedJwtException e) {
            logger.error("Token没有被正确构造: {} " + e);
            throw new TokenException("Token没有被正确构造");
            //return403(response,"Token没有被正确构造");
        } catch (SignatureException e) {
            logger.error("签名失败: {} " + e);
            throw new TokenException("签名失败");
            //return403(response,"签名失败");
        } catch (IllegalArgumentException e) {
            logger.error("非法参数异常: {} " + e);
            throw new TokenException("非法参数异常");
            //return403(response,"非法参数异常");
        }catch (Exception e){
            logger.info("app端校验token异常");
        }
        return null;
    }

    @Resource(name = "roleInfoMenusServiceImpl")
    public void
    setRoleInfoMenusService(IRoleInfoMenusService roleInfoMenusService) {
        this.roleInfoMenusService = roleInfoMenusService;
    }

    @Resource(name = "menuInfoServiceImpl")
    public void
    setMenuInfoService(IMenuInfoService menuInfoService) {
        this.menuInfoService = menuInfoService;
    }

    @SuppressWarnings("rawtypes")
    private void return403(HttpServletResponse response, String msg) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        ServerResponse response2 = ServerResponse.createByErrorCodeMessage(403, msg);
        try {
            out = response.getWriter();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        out.append(JSONObject.toJSONString(response2));
        if (out != null) {
            out.close();
        }
    }
    @SuppressWarnings("rawtypes")
    private void return505(HttpServletResponse response, String msg) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = null;
        ServerResponse response2 = ServerResponse.createBySuccessMessage(msg);
        response2.setStatus(505);
        try {
            out = response.getWriter();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        out.append(JSONObject.toJSONString(response2));
        if (out != null) {
            out.close();
        }
    }


}
